/*
Spotter Exercise Manager
Copyright 2011 Evan Nelson.

This file is part of Spotter Exercise Manager.

Spotter Exercise Manager is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Spotter Exercise Manager is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Spotter Exercise Manager.  If not, see <http://www.gnu.org/licenses/>.

The author can be contacted by emailing ean5533@gmail.com
*/

#include "database.h"
#include "settings.h"
#include <QMessageBox>
#include <QFile>
#include <QDir>
#include <QTextStream>
#include <QSqlError>

Database* Database::pInstance = 0;

Database::Database()
{

}

Database* Database::instance ()
{
    return pInstance ? pInstance : (pInstance = new Database);
}

QString Database::getDBFilePath() {
    return Settings::DB_PATH + "/spotter_" + QString::number(instance()->curPersonID) + ".db";
}

void Database::createDatabase(bool useSampleData) {
    //make sure data directory exists
    QDir dirHome = QDir(Settings::DB_PATH);
    if(!dirHome.exists()) {
        if(!dirHome.mkpath(dirHome.absolutePath())){
            QMessageBox("Unable to create data folder", "Failed to create data folder (path: " + dirHome.absolutePath() + ").",
                QMessageBox::Critical, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton).exec();
            return;
        }
    }

    QString targetPath = getDBFilePath();

    //make sure the DB file path is writeable
    if(!QFile(Settings::FILE_BASE_DB).copy(targetPath)) {
        QMessageBox("Unable to create user data file", "Failed to create user data file (path: " + targetPath + ").",
            QMessageBox::Critical, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton).exec();
        return;
    }

    QFile(targetPath).setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther);

    if(!openDatabase()) return;

    //execute scripts to populate tables
    QFile* script = new QFile(Settings::SCRIPT_IMPORT_BASE_DATA);
    executeScript(script);
    delete script;

    if(useSampleData) {
        script = new QFile(Settings::SCRIPT_IMPORT_SAMPLE_DATA);
        executeScript(script);
        delete script;
    }
}

bool Database::executeScript(QFile* file) {
    //note: This function is not a script parser. It will not handle anything more complicated than a set of statements separated by semi-colons
    instance()->db.transaction();

    bool ok = TRUE;
    QSqlQuery query;
    if(!file->isOpen()) {
        if(!file->open(QIODevice::ReadOnly)) return false;
    }
    QString script = file->readAll();

    QStringList statements = script.split(";", QString::SkipEmptyParts);
    QString curstatement;
    for (int i = 0; i < statements.count() && ok; i++)
    {
        if(statements[i].trimmed().isEmpty()) continue;
        curstatement = statements[i];
        ok = query.exec(statements[i]);
    }

    if(ok)
    {
        ok = pInstance->db.commit();
    }

    if(!ok)
    {
        QMessageBox::critical(0, "Error", query.lastError().text());
        pInstance->db.rollback();
    }

    return ok;
}

bool Database::openDatabase() {

    if(instance()->db.isOpen()) {
        //don't re-open the database
        return true;
    }

    instance()->db = QSqlDatabase::addDatabase("QSQLITE");
    instance()->db.setDatabaseName(getDBFilePath());

    bool ok = instance()->db.open();

    if(!ok) {
        QMessageBox("Cannot connect", "Cannot connect to sqlite database named " +  getDBFilePath() + ".",
            QMessageBox::Critical, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton).exec();
    }

    return ok;
}

void Database::closeDatabase() {
    if(!instance()->db.isOpen()) return;
    instance()->db.close();
}

int Database::getCurPersonID() {
    return instance()->curPersonID;
}

void Database::setCurPersonID(int personID) {
    instance()->curPersonID = personID;
}

QSqlQuery* Database::prepareQuery(const QString &sQuery) {
    QSqlQuery *newQuery = new QSqlQuery();
    newQuery->prepare(sQuery);
    return newQuery;
}
